package com.example.edu.school;

import com.example.edu.school.visitor.Visitor;
import com.example.edu.school.visitor.impl.ParentVisitor;
import com.example.edu.school.visitor.impl.PrincipalVisitor;

/**
 * 访问者模式包含五个要素：
 * <ul>
 *     <li>抽象-被访问者（Visitable），定义了accept方法，参数接收访问者</li>
 *     <li>实现-被访问者（VisitableImpl），实现抽象被访问者，accept方法体通常实现：Visitor.visit(this);</li>
 *     <li>
 *         抽象-访问者（Visitor），定义visit方法，参数接收被访问者实现类（缺点），抽象访问者的visit重载个数等于被访问者实现类个数（缺点），
 *         通过多态进行方法分派，实现方法调用
 *     </li>
 *     <li>实现-访问者（VisitorImpl），实现visit方法，真正操作被访问者的数据</li>
 *     <li>数据对象，维护被访问者的数据集合，并对外暴露方法，接收访问者，遍历被访问者数据集合，调用accept方法</li>
 * </ul>
 * <p>
 * 优点：
 * <ul>
 *     <li>解耦数据结构与数据操作</li>
 *     <li>对访问者扩展性较好</li>
 * </ul>
 * <p>
 * 缺点：
 * <ul>
 *     <li>一旦新增被访问者，意味着访问者必须增加对应的visit重载，违背了开闭原则</li>
 *     <li>访问者的visit依赖了具体实现，违背了依赖倒置原则</li>
 *     <li>修改被访问者时，可能会大面积修改相应的访问者</li>
 * </ul>
 * <p>
 * 案例：校长、家属访问学生和教师的信息，校长和家属关注的信息不同。运行试一下。
 * <p>
 * 缺点体现：如果新增一个"实习教师"的被访问者，意味着要改很多地方
 */
public class SchoolMain {

    public static void main(String[] args) {
        final DataHolder dataHolder = new DataHolder();

        Visitor principal = new PrincipalVisitor();
        Visitor parent = new ParentVisitor();
        dataHolder.accept(principal);
        dataHolder.accept(parent);
    }

}
